package club.pchome.utils;

import club.pchome.constant.Constant;
import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import java.security.Key;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author junao.yuan
 * @date 16-8-11
 */
public class JwtUtils {

	private static final String CLAIMS_KEY = "JWT_BODY";
	private static final String JWT_ISSUER = "CLUB_PCHOME_CHEFPK";
	private static final Integer REDIS_TIME = 30*60;
	private static final long EXPIRATION_TIME = 120; //令牌过期时间，单位：s
	private static final Logger LOGGER = LoggerFactory.getLogger(JwtUtils.class);


	private static Key checkKey(){

		return new SecretKeySpec(Constant.signKey.getBytes(), SignatureAlgorithm.HS512.getJcaName());
	}


	/**
	 * 创建Token
	 * @param jwtToken
	 * @return
	 */
	public static String createToken(JwtToken jwtToken) {
		jwtToken.setExpire(System.currentTimeMillis() + EXPIRATION_TIME);
		Map<String,Object> cl = new HashMap<String, Object>();
		cl.put(CLAIMS_KEY, JSONObject.toJSONString(jwtToken));

		return Jwts.builder().setClaims(cl)
							.setIssuer(JWT_ISSUER)
							.setIssuedAt(new Date(System.currentTimeMillis()))
							.signWith(SignatureAlgorithm.HS512, checkKey())
							.compact();
	}

	/**
	 *
	 * @param httpServletRequest
	 * @return
	 * @throws Exception
	 */
	public static JwtToken parseToken(HttpServletRequest httpServletRequest) throws Exception {
		if(httpServletRequest.getAttribute("jwtToken")!=null){
			return (JwtToken) httpServletRequest.getAttribute("jwtToken");
		}
		return null;
	}

	/**
	 * 解析TOken
	 * @param token
	 * @return
	 * @throws Exception
	 */
	public static JwtToken parseToken(String token) throws Exception {
		String json = (String) Jwts.parser().setSigningKey(checkKey()).parseClaimsJws(token).getBody().get(CLAIMS_KEY);
		return JSONObject.parseObject(json, JwtToken.class);
	}

	/**
	 * 刷新Token
	 * @throws Exception
	 */
	public static void refrechToken(String token) throws Exception {
		JwtToken jwtToken = parseToken(token);
		RedisUtil redisUtil = (RedisUtil) ApplicationContextUtil.getBean(RedisUtil.class);
		redisUtil.set(jwtToken.getToken(), token, REDIS_TIME);
	}


	/**
	 * 踢除TOken 并存入新Token
	 * @param jwtToken
	 * @throws Exception
	 */
	public static String awayToken(JwtToken jwtToken) throws Exception {
		RedisUtil redisUtil = (RedisUtil) ApplicationContextUtil.getBean(RedisUtil.class);
		String newToken = null;
		String token = redisUtil.get(jwtToken.getToken()).toString();
		if(!StringUtils.isEmpty(token)){
			JwtToken oldJwt = parseToken(token);
			if(oldJwt.getUserId().equals(jwtToken.getUserId())){
				redisUtil.del(oldJwt.getToken());
				newToken = createToken(jwtToken);
				LOGGER.info("踢除上一次登录信息",oldJwt);
			}
			else{
				newToken = token;
			}
		}
		else{
			newToken = createToken(jwtToken);
		}
		redisUtil.set(jwtToken.getToken(), newToken, REDIS_TIME);
		LOGGER.info("jwtTokenId:"+jwtToken.getToken());
		LOGGER.info("jwtTokenVal:"+redisUtil.get(jwtToken.getToken()));
		return newToken;
	}

	/**
	 * 获取jwt的payload部分
	 * @param token
	 * @return
	 */
	public static Claims getClaimFromToken(String token) {
		return Jwts.parser()
				.setSigningKey(checkKey())
				.parseClaimsJws(token)
				.getBody();
	}

	/**
	 * <pre>
	 *  验证token是否失效
	 *  true:过期 false:没过期
	 *  由于没有设置token的过期时间,这里用redis验证
	 * </pre>
	 */
	public static boolean isTokenExpired(String token) {
		final Date expiration = getExpirationDateFromToken(token);
		System.out.println(expiration.getTime());
		return expiration.before(new Date());
	}

	/**
	 * 获取token失效时间
	 * @param token
	 * @return
	 */
	public static Date getExpirationDateFromToken(String token) {
		try {
			//注意这里要是失效会报错
			return getClaimFromToken(token).getExpiration();
		}catch (Exception e){
			return new Date(0);
		}
	}


	public static void main(String[] args) throws Exception {
		JwtToken jwtToken = new JwtToken();

		String token = "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJDTFVCX1BDSE9NRV9DSEVGUEsiLCJKV1RfQk9EWSI6IntcImRldmljZVwiOlwicGNcIixcImV4cGlyZVwiOjE1Nzc5MzgzNzE1NjAsXCJ0aW1lc3RhbXBcIjpcIjIwMjAtMDEtMDIgMTI6MTI6NDRcIixcInVzZXJJZFwiOjN9IiwiZXhwIjoxNTc3OTM4MzcxLCJpYXQiOjE1Nzc5MzgzNjR9.cLSmSNa-6_wiqOatOYp9_T3xbWeAIfFgSG0Z9aUla_tdOc3vZFwCUabYuc8shze8fv6KFp_RJyfPOW_OEs0l0A";

		System.out.println(DateUtil.YYYY_MM_DD_MM_HH_SS.format(getExpirationDateFromToken(token)));
	}




}
